package Protocolo;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;

import Constants.ProtocolConsts;


public class Packet {

	private int field[];
	private InetAddress address;
	private int port;
	private ByteArrayInputStream bis;
	private int dataLength;
	
	public Packet() {
		
	}

	public Packet(DatagramPacket receivePacket) {
		byte[] receiveData = receivePacket.getData();
		int field[] = new int[7];
		//byteArrayToInt(buffer, field, bytes, flagId);
		field[ProtocolConsts._NUM_SEQ] = ProtocolConsts.byteArrayToInt(receiveData, 0, 4, -1);
		field[ProtocolConsts._NUM_REC] = ProtocolConsts.byteArrayToInt(receiveData, 1, 4, -1);
		field[ProtocolConsts._FLAG_ACK] = ProtocolConsts.byteArrayToInt(receiveData, 2, 1, 0);
		field[ProtocolConsts._FLAG_RST] = ProtocolConsts.byteArrayToInt(receiveData, 2, 1, 1);
		field[ProtocolConsts._FLAG_SYN] = ProtocolConsts.byteArrayToInt(receiveData, 2, 1, 2);
		field[ProtocolConsts._FLAG_FIN] = ProtocolConsts.byteArrayToInt(receiveData, 2, 1, 3);
		field[ProtocolConsts._JAN_RCPT] = ProtocolConsts.byteArrayToInt(receiveData, 3, 2, -1);
		ByteArrayInputStream bis = new ByteArrayInputStream(receiveData, 0, receivePacket.getLength());
		bis.skip(ProtocolConsts._HEADER_SIZE);

		this.field = field;
		this.address = receivePacket.getAddress();
		this.port = receivePacket.getPort();
		this.bis = bis;
		this.dataLength = receivePacket.getLength();
	}

	public int[] getField() {
		return this.field;
	}

	public InetAddress getAddress() {
		return this.address;
	}

	public int getPort() {
		return this.port;
	}

	public ByteArrayInputStream getBis() {
		return this.bis;
	}

	public int getDataLength() {
		return this.dataLength;
	}
	
	public boolean isAck() {
		return (this.getField()[ProtocolConsts._FLAG_ACK]==1)? true : false;
	}
	
	public boolean isSyn() {
		return (this.getField()[ProtocolConsts._FLAG_SYN]==1)? true : false;
	}
	
	public boolean isFin() {
		return (this.getField()[ProtocolConsts._FLAG_FIN]==1)? true : false;
	}
	
	public DatagramPacket createDatagramSocket(int field[], byte data[], InetAddress toAddress, int toPort) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		bos.write(ProtocolConsts.intToByteArray(field[ProtocolConsts._NUM_SEQ], 4));
		bos.write(ProtocolConsts.intToByteArray(field[ProtocolConsts._NUM_REC], 4));
		bos.write(ProtocolConsts.intToByteArray((field[ProtocolConsts._FLAG_ACK]<<7)|(field[ProtocolConsts._FLAG_RST]<<6)|(field[ProtocolConsts._FLAG_SYN]<<5)|(field[ProtocolConsts._FLAG_FIN]<<4), 1));
		bos.write(ProtocolConsts.intToByteArray(field[ProtocolConsts._JAN_RCPT], 2));
		if (data != null)
			bos.write(data);

		byte sendData[] = new byte[ProtocolConsts._HEADER_SIZE + ProtocolConsts._MSS];
		sendData = bos.toByteArray();
		return new DatagramPacket(sendData, sendData.length, toAddress, toPort);
	}
	
	public static int[] makePacketField(int numSeq, int numRec, int flags, int janRcpt) {
		int field[] = new int[7];
		field[ProtocolConsts._NUM_SEQ] = numSeq;
		field[ProtocolConsts._NUM_REC] = numRec;
		field[ProtocolConsts._FLAG_ACK] = flags&ProtocolConsts._BIT_ACK;
		field[ProtocolConsts._FLAG_RST] = (flags&ProtocolConsts._BIT_RST)>>1;
		field[ProtocolConsts._FLAG_SYN] = (flags&ProtocolConsts._BIT_SYN)>>2;
		field[ProtocolConsts._FLAG_FIN] = (flags&ProtocolConsts._BIT_FIN)>>3;
		field[ProtocolConsts._JAN_RCPT] = janRcpt;
		return field;
	}
}
